package com.xiyuan.smartutils;

import com.xiyuan.smartutils.constants.CodeConstants;
import com.xiyuan.smartutils.constants.EnumConstants;
import com.xiyuan.smartutils.constants.RegexpConstants;

import java.lang.reflect.Array;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 验证相关工具类 1.继承Validatex类，实现基于正则表达式的验证 2.创建Validates类，实现扩展的方法验证
 *
 * @version v1.0.0 @author lgz 2017-8-27 新建与整理
 */

@SuppressWarnings("ALL")
public class Validates implements CodeConstants, EnumConstants, RegexpConstants {
    
    /*************************************/
    // 字符验证
    /*************************************/
    /**
     * 比较两个字符是否相同
     *
     * @param c1              字符1
     * @param c2              字符2
     * @param caseInsensitive 是否忽略大小写
     * @return 是否相同
     */
    public static boolean equals(char c1, char c2, boolean caseInsensitive) {
        if (caseInsensitive) {
            return Character.toLowerCase(c1) == Character.toLowerCase(c2);
        }
        return c1 == c2;
    }
    /**
     * 是否空白字符，小于等于32认为是空白字符，12288是中文大写空格,65279是BOM头空格
     */
    public static boolean isWhitespace(char c) {
        switch (c){
            
            case _SPACE_:
            case _SPACE_ZH_:
            case _SPACE_BOM_:
            case _SPACE_EN_:
            case _SPACE_IDEOGRAPHIC_:
            case '\u0000':
                // issue#I5UGSQ，Hangul Filler
            case '\u3164':
                // MONGOLIAN VOWEL SEPARATOR
            case '\u180e':
                    return true;
            default:
                return Character.isWhitespace(c);
        }
    }
    
    /**
     * 如果s中存在c,则返回true,否则返回false
     */
    public static boolean isCharInString(char c, String s) {
        return (s.indexOf(c) != -1);
    }
    
    /**
     * 检查字符是否是大写字母,(注:A-Z之间)
     */
    public static boolean isLetterUppercase(char c) {
        return _LETTERS_UPPERCASE_.indexOf(c) != -1;
    }
    
    /**
     * 检查字符是否是大写字母加数字,(注:A-Z,0-9之间)
     */
    public static boolean isLetterUppercaseDigits(char c) {
        return _LETTERS_UPPERCASE_DIGITS_.indexOf(c) != -1;
    }
    
    /**
     * 检查字符是否是小写字母,(注:a-z之间)
     */
    public static boolean isLetterLowercase(char c) {
        return _LETTERS_LOWERCASE_.indexOf(c) != -1;
    }
    
    /**
     * 检查字符是否是小写字母加数字,(注:a-z,0-9之间)
     */
    public static boolean isLetterLowercaseDigits(char c) {
        return _LETTERS_LOWERCASE_DIGITS_.indexOf(c) != -1;
    }
    
    /**
     * 检查字符是否是字母,(注:a-z,A-Z之间)
     */
    public static boolean isLetter(char c) {
        return _LETTERS_.indexOf(c) != -1;
    }
    
    /**
     * 检查字符是否是数字
     */
    public static boolean isDigit(char c) {
        return _DIGITS_.indexOf(c) != -1;
    }
    
    /**
     * 检查字符是否是数字或小数点
     */
    public static boolean isDigitOrDot(char c) {
        return isDigit(c) || c == '.';
    }
    
    /**
     * 检查字符是否是数字或字母
     */
    public static boolean isLetterOrDigit(char c) {
        return _LETTERS_DIGITS_.indexOf(c) != -1;
    }
    
    /**
     * 判断是否为emoji表情符<br>
     *
     * @param c 字符
     * @return 是否为emoji
     * 
     */
    public static boolean isEmoji(char c) {
        return false == ((c == 0x0) ||
                (c == 0x9) ||
                (c == 0xA) ||
                (c == 0xD) ||
                ((c >= 0x20) && (c <= 0xD7FF)) ||
                ((c >= 0xE000) && (c <= 0xFFFD)) ||
                ((c >= 0x100000) && (c <= 0x10FFFF)));
    }
    /*************************************/
    // 基础判断
    /*************************************/
    
    /**
     * 是否Windows
     */
    public static boolean isWindows() {
        return Systems.isWindows();
    }
    
    /**
     * 是否MacOS
     */
    public static boolean isMacOS() {
        return Systems.isMacOS();
    }
    
    /**
     * 是否Linux
     */
    public static boolean isLinux() {
        return Systems.isLinux();
    }
    
    /**
     * 检查两个对象是否相等
     */
    public static boolean isEqual(Object obj, Object obj2) {
        
        if (obj == null) return obj2 == null;
        
        if (obj2 == null) return false;
        
        if (obj.getClass() != obj2.getClass()) {
            return false;
        }
        
        return obj.equals(obj2);
    }
    
    /**
     * 检查两个对象是否相等
     */
    public static boolean isNotEqual(Object obj, Object obj2) {
        return !isEqual(obj, obj2);
    }
    
    /**
     * 检查两个字符串是否忽略大小写相等
     */
    public static boolean isEqualIgnoreCase(String str, String str2) {
        return (str == null) ? str2 == null : str.equalsIgnoreCase(str2);
    }
    
    /**
     * 检查src是否包括str
     */
    public static boolean isContain(String src, String str) {
        return (src == null) ? (str == null) : (src.indexOf(str) != -1);
    }
    
    /**
     * 检查对象是否为空
     */
    public static boolean isEmpty(Object obj) {
        if (obj == null) return true;
        if (obj instanceof String) return isEmpty((String) obj);
        
        if (obj instanceof Collection) return ((Collection<?>) obj).isEmpty();
        
        if (obj instanceof Map) return ((Map<?, ?>) obj).isEmpty();
        
        if (Types.isArray(obj)) return Array.getLength(obj) == 0;
        
        if (obj instanceof AtomicIntegerArray) return ((AtomicIntegerArray) obj).length() == 0;
        
        if (obj instanceof AtomicLongArray) return ((AtomicLongArray) obj).length() == 0;
        
        if (obj instanceof AtomicReferenceArray) return ((AtomicReferenceArray) obj).length() == 0;
        
        return false;
    }
    
    /**
     * 检查字符串是否为空，null或空字符串
     */
    public static boolean isEmpty(CharSequence s) {
        return s == null || s.length() == 0;
    }
    
    /**
     * 检查字符串是否为空白字符串
     */
    public static boolean isBlank(CharSequence s) {
        int i = 0, l = s == null ? 0 : s.length();
        while (i < l && isWhitespace(s.charAt(i))) i++;
        return i == l;
    }
    
    /**
     * 检查字符串是否不为空，即不为null和空白字符串
     */
    public static boolean isNotBlank(CharSequence s) {
        return !isBlank(s);
    }
    
    /**
     * 检查集合是否为null或空
     */
    public static boolean isEmpty(Collection<?> c) {
        return c == null || c.isEmpty();
    }
    
    /**
     * 检查数组是否为null或空
     */
    public static boolean isEmpty(Object[] s) {
        return s == null || s.length == 0;
    }
    
    /**
     * 检查字符串是否不为空，即不为null和空字符串
     */
    public static boolean isNotEmpty(CharSequence s) {
        return !isEmpty(s);
    }
    
    
    /**
     * 检查集合是否不为空
     */
    public static boolean isNotEmpty(Collection<?> c) {
        return !isEmpty(c);
    }
    
    /**
     * 检查是否不为空
     */
    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }
    
    /**
     * 检查是否是指定的长度，注:当s=null || s="",min=0时为true
     */
    public static boolean isLen(CharSequence s, int min, int max) {
        if (isEmpty(s)) {
            return min == 0;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查是否GBK编码长度，字母占1个，汉字占2个
     */
    public static boolean isByteLen(String s, int min, int max) {
        return isByteLen(s, min, max, _GBK_);
    }
    
    /**
     * 检查是否指定编码长度，UTF-8是一个汉字3个字节，GBK是两个
     */
    public static boolean isByteLen(String s, int min, int max, String encoding) {
        if (isEmpty(s)) {
            return min == 0;
        }
        
        int len = Bytes.getByteLen(s, encoding);
        return (len >= min && len <= max);
    }
    
    /**
     * 检查是否在指定的字符串内
     */
    public static boolean isScope(String s, String scope) {
        if (isEmpty(s)) {
            return false;
        }
        
        // 逐个字符检查,如果发现一个不是specifyStr,则返回false
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            
            if (!isCharInString(c, scope)) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 检查是否是正确的电话号码
     */
    public static boolean isPhone(String s) {
        return isScope(s, _PHONE_NUMBER_CHARS);
    }
    
    /**
     * 检查是否是有效的颜色
     */
    public static boolean isColor(String s) {
        if (!Validates.isLen(s, 7, 7) || !s.startsWith("#")) {
            return false;
        }
        
        s = s.substring(1);
        return isScope(s, _DIGITS_HEX_);
    }
    
    /**
     * 是否包含多字节字符
     */
    public static boolean isContainMultByteChar(String s) {
        if (isEmpty(s)) {
            return false;
        }
        
        int len = s.length();
        for (int i = 0; i < len; i++) {
            if ((int) s.charAt(i) > 127) {
                return true;
            }
        }
        
        return false;
    }
    
    private static String trim(String s, String prefix, String suffix) {
        if (Validates.isEmpty(s)) {
            return s;
        }
        
        int s1 = 0, s2 = s.length();
        boolean flag = false;
        if (!Validates.isEmpty(prefix) && s.startsWith(prefix)) {
            s1 = prefix.length();
            flag = true;
        }
        
        if (!Validates.isEmpty(suffix) && s.endsWith(suffix)) {
            s2 -= suffix.length();
            flag = true;
        }
        
        return !flag ? s : s.substring(s1, s2);
    }
    /*************************************/
    // 正则表达式相关
    /*************************************/
    /**
     * 正则表达式验证
     *
     * @param regexp 正则表达式
     * @param value  需要验证的值
     * @return =true表示成功,=false表示失败
     */
    public static boolean isRegexp(Pattern regexp, String value, boolean allowEmpty) {
        if (Validates.isEmpty(value)) return allowEmpty;
        return regexp.matcher(value).matches();
    }
    
    /**
     * 检查是否符合正则表达式
     */
    public static boolean isRegexp(Pattern regexp, String s) {
        return isRegexp(regexp, s, false);
    }
    
    /**
     * 正则表达式验证
     *
     * @param regexp 正则表达式
     * @param value  需要验证的值
     * @return =true表示成功,=false表示失败
     */
    public static boolean isRegexp(String regexp, String value, boolean allowEmpty) {
        regexp = trim(regexp, "/", "/");
        return isRegexp(Pattern.compile(regexp),value,allowEmpty);
    }
    
   
    
    /**
     * 检查是否符合正则表达式
     */
    public static boolean isRegexp(String regexp, String s) {
        return isRegexp(regexp, s, false);
    }
    /**
     * 判断是否为true,
     *
     * @param obj 参数
     * @return true if obj is true or obj equals "true" or obj is 1 or obj equals "1"
     */
    public static boolean isTrue(String obj) {
        if (obj == null) return false;
        return "true".equals(obj) || "1".equals(obj);
    }
    
    /**
     * 判断是否为true,
     *
     * @param obj 参数
     * @return true if obj is 1
     */
    public static boolean isTrue(int obj) {
        return obj == 1;
    }
    
    /**
     * 判断是否为true,
     *
     * @param obj 参数
     * @return true if obj is true or obj equals "true" or obj is 1 or obj equals "1"
     */
    public static boolean isTrue(Object obj) {
        if (obj == null) return false;
        if (obj instanceof Boolean) return ((Boolean) obj).booleanValue();
        if (obj instanceof Number) return ((Number) obj).intValue() == 1;
        return isTrue(String.valueOf(obj));
    }
    
    /**
     * 是否是布尔型 true|false
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isBoolean(String value, boolean allowEmpty) {
        if (Validates.isEmpty(value)) {return allowEmpty;}
        
        return "true".equals(value) || "false".equals(value);
    }
    
    /**
     * 是否是数字
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isNumeric(String value, boolean allowEmpty) {
        return isRegexp(NUMERIC, value, allowEmpty);
    }
    
    /**
     * 是否整数，包括(正整数、负整数、0)，支持+-号
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isInteger(String value, boolean allowEmpty) {
        return isRegexp(INTEGER, value, allowEmpty);
    }
    
    /**
     * 是否正整数，包括(>0的整数)，不支持+号，全数字
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isIntegerPositive(String value, boolean allowEmpty) {
        return isRegexp(INTEGER_P, value, allowEmpty);
    }
    
    /**
     * 是否负整数，包括(<0的整数)，-号开头，再[1-9]，再[0-9]*
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isIntegerNegative(String value, boolean allowEmpty) {
        return isRegexp(INTEGER_N, value, allowEmpty);
    }
    
    /**
     * 是否非负整数，包括(>=0的整数)，不支持+号，全数字
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isIntegerNonnegative(String value, boolean allowEmpty) {
        return isRegexp(INTEGER_N_N, value, allowEmpty);
    }
    
    /**
     * 是否非正整数，包括(<=0的整数)，负数必须-号开头
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isIntegerNonpositive(String value, boolean allowEmpty) {
        return isRegexp(INTEGER_N_P, value, allowEmpty);
    }
    
    /**
     * 是否是字母组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphabetic(String value, boolean allowEmpty) {
        return isRegexp(ALPHABAT, value, allowEmpty);
    }
    
    /**
     * 是否是大写字母组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphabeticUppercase(String value, boolean allowEmpty) {
        return isRegexp(ALPHABAT_UPPER, value, allowEmpty);
    }
    
    /**
     * 是否是小写字母组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphabeticLowercase(String value, boolean allowEmpty) {
        return isRegexp(ALPHABAT_LOWER, value, allowEmpty);
    }
    
    /**
     * 是否是字母和数字组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaNumeric(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_NUMERIC, value, allowEmpty);
    }
    
    /**
     * 是否是字母和数字组合，字母开头
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaNumericPA(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_NUMERIC_PA, value, allowEmpty);
    }
    
    /**
     * 是否是字母和数字或下划线组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaNumericUl(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_NUMERIC_UL, value, allowEmpty);
    }
    
    /**
     * 是否是字母和数字或点号组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaNumericDot(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_NUMERIC_DOT, value, allowEmpty);
    }
    
    /**
     * 是否是字母和数字或(.-_~四个非特殊URL字符)组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaNumericUrl(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_NUMERIC_URL, value, allowEmpty);
    }
    
    /**
     * 是否是字母和数字组合，字母或下划线开头，java命名规则
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaNumericUlPA(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_NUMERIC_UL_PA, value, allowEmpty);
    }
    
    /**
     * 是否是字母和数字组合，字母或下划线或$开头，js命名规则
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaNumericUlDlPA(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_NUMERIC_UL_DL_PA, value, allowEmpty);
    }
    
    /**
     * 是否是大写字母和数字组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaUpperNumeric(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_UPPER_NUMERIC, value, allowEmpty);
    }
    
    /**
     * 是否是小写字母和数字组合
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAlphaLowerNumeric(String value, boolean allowEmpty) {
        return isRegexp(ALPHA_LOWER_NUMERIC, value, allowEmpty);
    }
    
    /**
     * 是否浮点型，支持多位小数，支持正负号前缀，如-12,-12.3,+12.35,-12.356,12,12.3,12.35,0,0.3,0.35,-0.3,-0.35
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isFloat(String value, boolean allowEmpty) {
        return isRegexp(FLOAT, value, allowEmpty);
    }
    
    /**
     * 是否是最长两位小数的金额，支持正负号前缀，如-12,-12.3,+12.35,12,12.3,12.35,0,0.3,0.35,-0.3,-0.35
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isAmount2R(String value, boolean allowEmpty) {
        return isRegexp(AMOUNT_2R, value, allowEmpty);
    }
    
    /**
     * 是否是邮箱地址，支持类似于xxx@xxx.xxx的邮箱格式，支持[-_.]等连接符，不支持中文等特殊符号
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isEmail(String value, boolean allowEmpty) {
        return isRegexp(EMAIL, value, allowEmpty);
    }
    
    /**
     * 是否是IP地址，支持类似于192.168.1.1/192.168.01.01/192.168.001.001的IP格式
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isIP(String value, boolean allowEmpty) {
        return isRegexp(IP, value, allowEmpty);
    }
    
    /**
     * 是否是MAC地址，格式为23:ad:87:be(十六进制)
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isMacAddress(String value, boolean allowEmpty) {
        return isRegexp(MAC, value, allowEmpty);
    }
    
    /**
     * 是否是泛手机号码，支持前缀+86,86开头,后面接手机号
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isMobile(String value, boolean allowEmpty) {
        return isRegexp(MOBILE, value, allowEmpty);
    }
    
    /**
     * 是否是中国区11位的手机号码
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isMobile11(String value, boolean allowEmpty) {
        return isRegexp(MOBILE_11, value, allowEmpty);
    }
    
    /**
     * 是否是日期格式，格式为yyyy-MM-dd
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isDate(String value, boolean allowEmpty) {
        return isRegexp(DATE, value, allowEmpty);
    }
    
    /**
     * 是否是时间格式，格式为HH:mm:ss
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isTime(String value, boolean allowEmpty) {
        return isRegexp(TIME, value, allowEmpty);
    }
    
    /**
     * 是否是日期时间格式，格式为yyyy-MM-dd HH:mm:ss
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isDateTime(String value, boolean allowEmpty) {
        return isRegexp(DATE_TIME, value, allowEmpty);
    }
    
    /**
     * 是否是身份证号，格式为[0-9]{6}yyyyMMdd[0-9]{3}[0-9xX*]，前6位数字，中间8位1900-2099年的日期，末4位为3个数字和[0-9]或xX*。
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isIdcard(String value, boolean allowEmpty) {
        return isRegexp(IDCARD, value, allowEmpty);
    }
    
    /**
     * 是否是邮政编码
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isPostalCode(String value, boolean allowEmpty) {
        return isRegexp(POSTAL_CODE, value, allowEmpty);
    }
    
    /**
     * 是否是合适的用户编码
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isUserCode(String value, boolean allowEmpty) {
        return isRegexp(USER_CODE, value, allowEmpty);
    }
    
    /**
     * 是否是合适的用户密码
     *
     * @param value      需要验证的值
     * @param allowEmpty 是否允许为空
     * @return =true表示成功,=false表示失败
     */
    public static boolean isUserPass(String value, boolean allowEmpty) {
        return isRegexp(USER_PASS, value, allowEmpty);
    }
    

    
    /**
     * 检查是否是布尔型，true|false
     */
    public static boolean isBoolean(String s) {
        return isBoolean(s, false);
    }
    
    /**
     * 检查是否是数值型，允许0开头
     */
    public static boolean isNumeric(String s) {
        return isNumeric(s, false);
    }
    
    /**
     * 检查是否是数值型，允许0开头
     */
    public static boolean isNumeric(char c) {
        return isCharInString(c, _DIGITS_);
    }
    
    /**
     * 检查是否数值型，允许0开头且长度在指定范围内
     */
    public static boolean isNumericLen(String s, int min, int max) {
        if (!isNumeric(s, min == 0)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查是否是整型,包括(正整数、负整数、0)，支持+-号
     */
    public static boolean isInteger(String s) {
        return isInteger(s, false);
    }
    
    /**
     * 检查是否是一个正整数
     */
    public static boolean isIntegerPositive(String s) {
        return isIntegerPositive(s, false);
    }
    
    /**
     * 检查是否是一个非负整数
     */
    public static boolean isIntegerNonnegative(String s) {
        return isIntegerNonnegative(s, false);
    }
    
    /**
     * 检查是否是一个负整数
     */
    public static boolean isIntegerNegative(String s) {
        return isIntegerNegative(s, false);
    }
    
    /**
     * 检查是否是一个非正整数
     */
    public static boolean isIntegerNonpositive(String s) {
        return isIntegerNonpositive(s, false);
    }
    
    /**
     * 检查字符串是否是整型,且min <= s <= max
     */
    public static boolean isIntegerValue(String s, int min, int max) {
        if (!isInteger(s, false)) {
            return false;
        }
        
        int num = Integer.parseInt(s);
        return ((num >= min) && (num <= max));
    }
    
    /**
     * 检查字符串是否是非负整型,且min <= s.length() <= max
     */
    public static boolean isIntegerNonnegativeLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isIntegerNonnegative(s, false)) {
            return false;
        }
        
        return ((s.length() >= min) && (s.length() <= max));
    }
    
    /**
     * 检查字符串是否都是由字母组成
     */
    public static boolean isAlphabetic(String s) {
        return isAlphabetic(s, false);
    }
    
    /**
     * 检查字符串是否都是由小写字母组成
     */
    public static boolean isAlphabeticLowercase(String s) {
        return isAlphabeticLowercase(s, false);
    }
    
    /**
     * 检查字符串是否都是由大写字母组成
     */
    public static boolean isAlphabeticUppercase(String s) {
        return isAlphabeticUppercase(s, false);
    }
    
    /**
     * 检查字符串是否都是由字母组成且长度在min,max范围内
     */
    public static boolean isAlphabeticLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphabetic(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由小写字母组成且长度在min,max范围内
     */
    public static boolean isAlphabeticLowercaseLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphabeticLowercase(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由大字母组成且长度在min,max范围内
     */
    public static boolean isAlphabeticUpperLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphabeticUppercase(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由字母或数字组成
     */
    public static boolean isAlphaNumeric(String s) {
        return isAlphaNumeric(s, false);
    }
    
    /**
     * 检查字符串是否都是由字母或数字组成且长度在min,max范围内
     */
    public static boolean isAlphaNumericLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaNumeric(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由字母或数字组成，字母开头
     */
    public static boolean isAlphaNumericPA(String s) {
        return isAlphaNumericPA(s, false);
    }
    
    /**
     * 检查字符串是否都是由字母或数字组成，字母开头且长度在min,max范围内
     */
    public static boolean isAlphaNumericPALen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaNumericPA(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由字母或数字或下划线组成
     */
    public static boolean isAlphaNumericUl(String s) {
        return isAlphaNumericUl(s, false);
    }
    
    /**
     * 检查字符串是否都是由字母或数字或下划线组成，且长度在min,max范围内
     */
    public static boolean isAlphaNumericUlLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaNumericUl(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由字母或数字或点号组成，且长度在min,max范围内
     */
    public static boolean isAlphaNumericDotLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaNumericDot(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由字母或数字或(.-_~四个URL非特殊字符)组成，且长度在min,max范围内
     */
    public static boolean isAlphaNumericUrlLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaNumericUrl(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由字母或数字或下划线组成，字母或下划线开头
     */
    public static boolean isAlphaNumericUlPA(String s) {
        return isAlphaNumericUlPA(s, false);
    }
    
    /**
     * 检查字符串是否都是由字母或数字或下划线组成，字母或下划线开头且长度在min,max范围内
     */
    public static boolean isAlphaNumericUlPALen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaNumericUlPA(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由字母或数字或下划线或$组成，字母或下划线或$开头
     */
    public static boolean isAlphaNumericUlDlPA(String s) {
        return isAlphaNumericUlDlPA(s, false);
    }
    
    /**
     * 检查字符串是否都是由字母或数字或下划线或$组成，字母或下划线或$开头且长度在min,max范围内
     */
    public static boolean isAlphaNumericUlDlPALen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaNumericUlDlPA(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由大写字母或数字组成
     */
    public static boolean isAlphaUpperNumeric(String s) {
        return isAlphaUpperNumeric(s, false);
    }
    
    /**
     * 检查字符串是否都是由大写字母或数字组成
     */
    public static boolean isAlphaLowerNumeric(String s) {
        return isAlphaLowerNumeric(s, false);
    }
    
    /**
     * 检查字符串是否都是由大写字母或数字组成
     */
    public static boolean isAlphaUpperNumericLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaUpperNumeric(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否都是由小写字母或数字组成
     */
    public static boolean isAlphaLowerNumericLen(String s, int min, int max) {
        if (Validates.isEmpty(s)) {
            return min == 0;
        }
        
        if (!isAlphaLowerNumeric(s, false)) {
            return false;
        }
        
        return (s.length() >= min && s.length() <= max);
    }
    
    /**
     * 检查字符串是否由十六进制大小写字母和数字组成
     */
    public static boolean isHexString(String s) {
        return isRegexp(HEX, s, false);
    }
    
    /**
     * 检查字符串是否由十六进制大小写字母和数字组成16位类MD5字符串
     */
    public static boolean isMD5String(String s) {
        return isRegexp(MD5, s, false);
    }
    
    /**
     * 检查是否是一个浮点型,支持正负号前缀,不支持指点E
     */
    public static boolean isFloat(String s) {
        return isFloat(s, false);
    }
    
    /**
     * 检查字符串是否是整数、一位小数、或两位小数点的金额值
     */
    public static boolean isAmount2R(String s) {
        return isAmount2R(s, false);
    }
    
    /**
     * 检查是否是正确的手机号码
     */
    public static boolean isMobile(String s) {
        return isMobile(s, false);
    }
    
    /**
     * 判断号码是否符合配置文件所设条件
     *
     * @param s 号码字符串
     * @return boolean =true 是手机号码,=false 非手机号码
     */
    public static boolean isMobile11(String s) {
        return isMobile11(s, false);
    }
    
    /**
     * 检查是否是当天
     */
    public static boolean isCurrentDate(String date) {
        return DateTimes.getDateString().equals(date);
    }
    
    /**
     * 检查是否是正确的日期 格式为yyyy-MM-dd
     */
    public static boolean isDate(String date) {
        return isDate(date, false);
    }
    
    /**
     * 检查是否是正确的时间
     */
    public static boolean isTime(String time) {
        return isTime(time, false);
    }
    
    /**
     * 判断是不是指定的时间格式
     */
    public static boolean isDateTime(String datetime) {
        return isDateTime(datetime, false);
    }
    
    /**
     * 判断是否是18位身份证号码
     */
    public static boolean isIdcard(String idcard) {
        return isIdcard(idcard, false);
    }
    
    /**
     * 判断是否是合适的用户名（中文至少2个汉字，字符最小3字符，总长最大25）
     */
    public static boolean isUserName(String name) {
        return isRegexp(USER_CODE, name);
    }
    
    /**
     * 判断是否是合适的密码（大小字母数字和特殊符号四选三，6-16位）
     */
    public static boolean isUserPass(String password) {
        return isRegexp(USER_PASS, password);
    }
    
    /**
     * 检查字符串是否正确的邮件地址(注:要求存在@字符,且不是出现在第一个,最后一个位置,现在不检查是否存在".")
     */
    public static boolean isEmail(String s) {
        return isEmail(s, false);
    }
    
    /**
     * 检查是否是IP地址,ip为空返回false;
     */
    public static boolean isIP(String s) {
        return isIP(s, false);
    }
    
    /**
     * 检查是否是IP/MASK地址,ip/mask为空返回false;
     */
    public static boolean isIPMask(String s) {
        if (isBlank(s)) {
            return false;
        }
        
        s = s.trim();
        int ind = s.indexOf("/");
        if (ind == -1) {// 没有掩码，可以是一个IP或含*的IP，如192.168.0.3,192.168.000.023或者192.168.*.*
            String[] ipMaskValues = Arrays.toStringArray(s, "\\.");
            if (ipMaskValues.length != 4) {
                return false;
            }
            
            for (String ipMaskValue : ipMaskValues) {
                if ("*".equals(ipMaskValue)) {
                    continue;
                }
                
                if (!Validates.isNumericLen(ipMaskValue, 1, 3)) {
                    return false;// 数值型且000-999之间
                }
                
                int value = Integer.parseInt(ipMaskValue);
                if (value > 255) {
                    return false;// 数字且0-255之间
                }
            }
            
            return true;
        }
        else {// 有掩码，可以是192.168.0.3/24,或192.168.0.0/255.255.255.192
            String ipMaskIp = s.substring(0, ind).trim();
            String ipMaskMask = s.substring(ind + 1).trim();
            if (!isIP(ipMaskIp)) {
                return false;// 前面一段必须是IP
            }
            
            if (isIntegerNonnegative(ipMaskMask)) {// 如果是非负整数，则在0-32之间
                return Integer.parseInt(ipMaskMask) <= 32;
            }
            else {// 不是数字，则是IP地址掩码，也是0-32，一共33种可能 @see IP_MASK
                if (!isIP(ipMaskMask)) {
                    return false;
                }
                
                return IPs.ipMaskToInt(ipMaskMask) != -1;
            }
        }
    }
    
    /**
     * 检查IP地址是否允许，支持指定白黑名单
     */
    public static boolean isIPAllowByWhiteBlackList(String ip, String ipWhiteList, String ipBlackList,
                                                    boolean defaultValue) {
        if (defaultValue) {// 默认开放，如果在黑名单中，则返回false
            if (isNotBlank(ipBlackList)) {
                List<String> ipList = Lists.toStringList(ipWhiteList);
                if (Validates.isContainIp(ipList, ip)) {
                    return false;
                }
            }
        }
        else {// 默认关闭，如果在白名单中，则返回true
            if (isNotBlank(ipWhiteList)) {
                List<String> ipList = Lists.toStringList(ipWhiteList);
                if (Validates.isContainIp(ipList, ip)) {
                    return true;
                }
            }
        }
        
        return defaultValue;
    }
    
    /**
     * 检查是否是macAddress,macAddress为空返回false;
     */
    public static boolean isMacAddress(String s) {
        return isMacAddress(s, false);
    }
    
    /**
     * 检查是否邮编
     */
    public static boolean isPostalCode(String s) {
        return isPostalCode(s, false);
    }
    
    /**
     * 验证是否为生日
     *
     * @param year  年，从1900年开始计算
     * @param month 月，从1开始计数
     * @param day   日，从1开始计数
     * @return 是否为生日
     */
    public static boolean isBirthday(int year, int month, int day) {
        // 验证年
        if (year < 1900) {
            return false;
        }
        
        // 验证月
        if (month < 1 || month > 12) {
            return false;
        }
        
        // 验证日
        if (day < 1 || day > 31) {
            return false;
        }
        // 检查几个特殊月的最大天数
        if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) {
            return false;
        }
        if (month == 2) {
            // 在2月，非闰年最大28，闰年最大29
            return day < 29 || (day == 29 && isLeapYear(year));
        }
        return true;
    }
    
    /**
     * 验证是否为生日<br>
     * 只支持以下几种格式：
     * <ul>
     * <li>yyyyMMdd</li>
     * <li>yyyy-MM-dd</li>
     * <li>yyyy/MM/dd</li>
     * <li>yyyy.MM.dd</li>
     * <li>yyyy年MM月dd日</li>
     * </ul>
     *
     * @param value 值
     * @return 是否为生日
     */
    public static boolean isBirthday(CharSequence value) {
        final Matcher matcher = BIRTHDAY.matcher(value);
        if (matcher.find()) {
            int year = Integer.parseInt(matcher.group(1));
            int month = Integer.parseInt(matcher.group(3));
            int day = Integer.parseInt(matcher.group(5));
            return isBirthday(year, month, day);
        }
        return false;
    }
    /************************************************************/
    // 日期判断
    /************************************************************/
    
    /**
     * 检查是否是正确的年
     */
    public static boolean isYear(String s) {
        if (!isNumeric(s)) {
            return false;
        }
        
        return ((s.length() == 2) || (s.length() == 4));
    }
    
    /**
     * 判断是否是周末 yyyy-MM-dd
     */
    public static boolean isWeekend(String date) {
        Calendar calendar = DateTimes.toCalendar(date + " 00:00:00");
        return calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY;
    }
    
    /**
     * 判断是否季度末 yyyy-MM-dd
     */
    public static boolean isMonthQuarter(String date) {
        if (!isDate(date)) return false;
        
        String year = date.substring(0, 4);
        String month = date.substring(5, 7);
        String day = date.substring(8);
        
        if (!isMonthLastDay(year, month, day)) {
            return false;
        }
        
        return "03".equals(month) || "06".equals(month) || "09".equals(month) || "12".equals(month);
    }
    
    /**
     * 判断是否年末 yyyy-MM-dd
     */
    public static boolean isYearLastDay(String date) {
        if (!isDate(date)) return false;
        
        String year = date.substring(0, 4);
        String month = date.substring(5, 7);
        String day = date.substring(8);
        
        if (!isMonthLastDay(year, month, day)) {
            return false;
        }
        
        return "12".equals(month);
    }
    
    /**
     * 检查是否是正确的月
     */
    public static boolean isMonth(String s) {
        if (isEmpty(s)) {
            return false;
        }
        
        return isIntegerValue(s, 1, 12);
    }
    
    /**
     * 检查是否是正确的日
     */
    public static boolean isDay(String s) {
        if (isEmpty(s)) {
            return false;
        }
        
        return isIntegerValue(s, 1, 31);
    }
    
    /**
     * 检查是否闰年
     */
    public static boolean isLeapYear(int year) {
        return (year % 4 == 0) && ((!(year % 100 == 0)) || (year % 400 == 0));
    }
    
    /**
     * 检查是否是月末 yyyy-MM-dd
     */
    public static boolean isMonthLastDay(String date) {
        if (!isDate(date)) {
            return false;
        }
        
        String year = date.substring(0, 4);
        String month = date.substring(5, 7);
        String day = date.substring(8);
        return isMonthLastDay(year, month, day);
    }
    
    /**
     * 检查是否是月末
     */
    public static boolean isMonthLastDay(String year, String month, String day) {
        if (!isDate(year, month, day)) {
            return false;
        }
        
        int yearInt = Integer.parseInt(year);
        int monthInt = Integer.parseInt(month);
        int dayInt = Integer.parseInt(day);
        return isMonthLastDay(yearInt, monthInt, dayInt);
    }
    
    /**
     * 检查是否是月末
     */
    public static boolean isMonthLastDay(int year, int month, int day) {
        if (year < 1000 || year > 9999 || month > 12 || month < 1 || day > 31 || day < 1) {
            return false;
        }
        
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                return day == 31;
            case 4:
            case 6:
            case 9:
            case 11:
                return day == 30;
            default:// 2月
                boolean isLeapYear = Validates.isLeapYear(year);
                return isLeapYear ? day == 29 : day == 28;
        }
    }
    
    /**
     * 检查是否是正确的时
     */
    public static boolean isHour(String s) {
        if (isEmpty(s)) {
            return false;
        }
        
        return isIntegerValue(s, 0, 23);
    }
    
    /**
     * 检查是否是正确的分
     */
    public static boolean isMinute(String s) {
        if (isEmpty(s)) {
            return false;
        }
        return isIntegerValue(s, 0, 59);
    }
    
    /**
     * 检查是否是正确的秒
     */
    public static boolean isSecond(String s) {
        if (isEmpty(s)) {
            return false;
        }
        return isIntegerValue(s, 0, 59);
    }
    
    /**
     * 检查是否是正确的日期
     */
    public static boolean isDate(String year, String month, String day) {
        if (!(isYear(year) && isMonth(month) && isDay(day))) {
            return false;
        }
        
        int intYear = Integer.parseInt(year);
        int intMonth = Integer.parseInt(month);
        int intDay = Integer.parseInt(day);
        
        if (intDay > _DAYS_IN_MONTH_[intMonth - 1]) {
            return false;
        }
        
        return (intMonth != 2) || (intDay <= (isLeapYear(intYear) ? 29 : 28));
    }
    
    /**
     * 判断是不是指定的时间格式, spe为日期分隔符
     */
    public static boolean isDateTime(String datetime, String spe) {
        if (isEmpty(datetime)) {
            return false;
        }
        
        datetime = datetime.replaceAll(spe, "-");
        return isDateTime(datetime);
    }
    
    /**
     * 检查是否是西方正确的日期
     */
    public static boolean isEnglishDate(String date) {
        if (isEmpty(date)) {
            return false;
        }
        
        date = date.replaceAll("/", "-");
        return isDate(date);
    }
    
    /**
     * 检查是否是日期比今天大
     */
    public static boolean isDateAfterToday(String date) {
        if (!isDate(date)) {
            return false;
        }
        
        String currentDate = DateTimes.getDateString();
        return date.compareTo(currentDate) > 0;
    }
    
    /**
     * 检查是否是日期比今天大等于
     */
    public static boolean isDateAfterEqualToday(String date) {
        if (!isDate(date)) {
            return false;
        }
        
        String currentDate = DateTimes.getDateString();
        return date.compareTo(currentDate) >= 0;
    }
    
    /**
     * 检查是否是正确的时间
     */
    public static boolean isTime(String hour, String minute, String second) {
        return isHour(hour) && isMinute(minute) && isSecond(second);
    }
    
    /**
     * 检查指定时间是否在当前时间规定的范围之内
     *
     * @param datetime          验证的时间，yyyy-MM-dd HH:mm:ss
     * @param differenceSeconds 范围值，单位秒，
     * @return =true表示在时间内，=false表示时间外
     */
    public static boolean isInTime(String datetime, int differenceSeconds) {
        long diffTime = System.currentTimeMillis() - DateTimes.toLong(datetime);
        return !((diffTime > 0 && diffTime > differenceSeconds * 1000L) || (diffTime < 0 && diffTime < -differenceSeconds * 1000L));
    }
    
    /*****************************************************/
    // URL判断，包括HTTP/HTTPS
    /*****************************************************/
    
    /**
     * 判断是否是有效的URL，支持http://和https://大小写开头
     */
    private static boolean startsWithIgnoreCase(String source, String cp) {
        if (source == null) {
            return cp == null;
        }
        else {
            return cp != null && source.toLowerCase().indexOf(cp) == 0;
        }
    }
    
    public static boolean isUrl(String s) {
        return startsWithIgnoreCase(s, "http://") || startsWithIgnoreCase(s, "https://");
    }
    
    /**
     * 判断是否是有效的http URL，支持http://大小写开头
     */
    public static boolean isHttp(String s) {
        return startsWithIgnoreCase(s, "http://");
    }
    
    /**
     * 判断是否是有效的https URL，支持https://大小写开头
     */
    public static boolean isHttps(String s) {
        return startsWithIgnoreCase(s, "https://");
    }
    
    /**
     * 是否是有效的文件名称
     */
    public static boolean isFileName(String fileName) {
        return isRegexp(FILE_NAME, fileName);
    }
    
    /*****************************************************/
    // 数组判断，包括关系
    /*****************************************************/
    
    /**
     * 字符串按分隔符方式，判断是否包含另一个字符串
     *
     * @param strs      原字符串
     * @param separator 字符串分隔符
     * @param str       另一字符串
     * @return =true表示包含,=false表示不包含
     */
    public static boolean isContain(String strs, String separator, String str) {
        String[] s = Arrays.toStringArray(strs, separator);
        return isContain(s, str);
    }
    
    /**
     * 字符串按分隔符方式，判断是否包含另一整型
     *
     * @param strs      原字符串
     * @param separator 字符串分隔符
     * @param i         另一字符串
     * @return =true表示包含,=false表示不包含
     */
    public static boolean isContain(String strs, String separator, int i) {
        int[] s = Arrays.toIntArray(strs, separator);
        return isContain(s, i);
    }
    
    /**
     * 字符串按分隔符方式，判断是否包含另一长整型
     *
     * @param strs      原字符串
     * @param separator 字符串分隔符
     * @param lo        另一长整型
     * @return =true表示包含,=false表示不包含
     */
    public static boolean isContain(String strs, String separator, long lo) {
        long[] s = Arrays.toLongArray(strs, separator);
        return isContain(s, lo);
    }
    
    /**
     * 字符串数组是否包含另一字符串
     *
     * @param strs 原字符串
     * @param str  另一字符串
     * @return =true表示包含,=false表示不包含
     */
    public static boolean isContain(String[] strs, String str) {
        if (str == null) {
            for (String s : strs) {
                if (s == null) {
                    return true;
                }
            }
        }
        else {
            for (String s : strs) {
                if (str.equals(s)) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    /**
     * 长整型数组是否包含另一长整型
     *
     * @param longs 原长整型数组
     * @param lo    另一长整型
     * @return =true表示包含,=false表示不包含
     */
    public static boolean isContain(long[] longs, long lo) {
        for (long l : longs) {
            if (l == lo) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 检查int是否在int[]内
     */
    public static boolean isContain(int[] ints, int io) {
        for (int i : ints) {
            if (i == io) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 检查object是否在列表中
     */
    public static boolean isContain(Collection<?> collection, Object o) {
        return Lists.contains(collection, o);
    }
    
    /**
     * 检查object是否在列表中对象的字段中
     */
    public static boolean isContain(Collection<?> collection, String field, Object o) {
        return Lists.contains(collection, field, o);
    }
    
    /**
     * 检查IP是否有包括IP掩码的IP集中
     */
    public static boolean isContainIp(List<String> ipMaskList, String ip) {
        if (!isIP(ip)) {
            return false;
        }
        
        for (String ipMask : ipMaskList) {
            if (isContainIp(ipMask, ip)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 检查IP是否有包括IP掩码的IP集中，注意如果ipMask和ip无效返回false
     */
    public static boolean isContainIp(String ipMask, String ip) {
        if (!isIP(ip) || !isIPMask(ipMask)) {
            return false;
        }
        
        // 本身就是IP
        if (ipMask.equals(ip)) {
            return true;
        }
        
        ip = IPs.trim(ip);
        int[] ipValues = Arrays.toIntArray(ip, "\\.");
        
        int ind = ipMask.indexOf("/");
        if (ind == -1) {// 没有掩码，格式为192.168.*.*
            String[] ipMaskValues = Arrays.toStringArray(ipMask, "\\.");
            for (int i = 0; i < ipMaskValues.length; i++) {
                if ("*".equals(ipMaskValues[i])) {
                    continue;
                }
                
                if (Integer.parseInt(ipMaskValues[i]) != ipValues[i]) {
                    return false;
                }
            }
            return true;
        }
        else {// 有掩码，格式为192.168.0.0/24，或192.168.0.0/255.255.255.192这两种，都转为int格式0-32
            String ipMaskIp = ipMask.substring(0, ind);
            String ipMaskMask = ipMask.substring(ind + 1);
            
            // 求得掩码值
            int ipMaskI = -1;
            if (isIntegerNonnegative(ipMaskMask)) {
                ipMaskI = Integer.parseInt(ipMaskMask);
            }
            else {
                ipMaskI = IPs.ipMaskToInt(ipMaskMask);
            }
            
            // 计算允许的最小最大IP值
            long[] minMaxIp = IPs.calcIpMaskMinMax(ipMaskIp, ipMaskI);
            long ipLong = IPs.ipToLong(ip);
            return ipLong >= minMaxIp[0] && ipLong <= minMaxIp[1];
        }
    }
    
    /**
     * 检查src是否包含字符串数组任何一个
     */
    public static boolean isStrContainStrArr(String src, String[] strs) {
        if (isEmpty(src)) return false;
        
        for (String str : strs) {
            if (src.contains(str)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 检查src是否包含字符串数组任何一个
     */
    public static boolean isStrContainStrArr(String src, String strs, String split) {
        return isStrContainStrArr(src, strs.split(split));
    }
    
    /**
     * 源src是否是含有通配符*的pattern能匹配上，如/abc/cde.gif匹配上/a*c/*de.*
     *
     * @param s        字符串
     * @param patterns 含通配符*的字符串数组，注意该方法中*至少占一个字符
     * @return true|false
     */
    public static boolean isMatch(String s, String... patterns) {
        for (String pattern : patterns) {
            if (isMatch(s, pattern)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 源src是否是含有通配符*的pattern能匹配上，如/abc/cde.gif匹配上/a*c/*de.*
     *
     * @param s       字符串
     * @param pattern 含通配符*的字符串数组，注意该方法中*至少占一个字符
     * @return true|false
     */
    public static boolean isMatch(String s, String pattern) {
        
        if (pattern == null) return s == null;
        if (s == null) return pattern == null;
        if (s.isEmpty()) return pattern.isEmpty();
        if (pattern.indexOf("*") == -1) return pattern.equals(s);
        
        String[] items = pattern.split("\\*");
        String last_pattern = "";
        for (int i = 0; i < items.length; i++) {
            
            last_pattern = items[i];
            if (last_pattern.isEmpty()) continue;
            
            int index = s.indexOf(last_pattern);
            if (index == -1) return false;
            s = s.substring(index + last_pattern.length());// 抹去前缀
        }
        
        if (s.isEmpty()) return true;
        
        // 若 '*' 为pattern最后一个字符 则返回true 反之返回是否已最后一个pattern 结尾
        return pattern.lastIndexOf("*") == (pattern.length() - 1) || s.endsWith(last_pattern);
    }
    
    /**
     * Returns
     *
     * @param str 字符串内容
     * @param allMatch 是否所有匹配才会 财务true
     * @param parttens 正则内容
     * @return true|false
     */
    public static boolean mm(String str, boolean allMatch, String... parttens) {
        String sp = ".";
        String deep = "\\*\\*";
        if (parttens == null || parttens.length == 0) return true;
        
        int mc = 0;
        int pc = 0;
        for (int i = 0; i < parttens.length; i++) {
            String partten = parttens[i];
            if (partten == null || partten.isEmpty()) {
                continue;
            }
            pc++;// 记录有效的 通配符数量
            int idx = 0;
            String[] pp = StrUtils.splitpt(partten, '.').toArray(new String[0]);
            boolean flag = false;
            for (int j = 0; j < pp.length; j++) {
                String p1 = pp[j];
                if (idx == str.length() - 1) {
                    if (!allMatch) {break;}
                    else {
                        // 字符串已结束
                        if (j < pp.length - 1) return false;// 说明后面还有字符匹配
                        
                        // aaa.bb.cc
                        // aaa.bb.cc* 或者
                        
                        // 这里需要 根据 当前通配符 是否允许 ****
                        return false;
                    }
                }
                int idx1 = str.indexOf(partten, idx);
                if (idx1 != idx) {
                    break;// 不匹配
                }
                
            }
            if (flag) mc++;
        }
        
        return false;
    }
    
    /***
     * 源src是否是符合java命名规则
     *
     * @param str 字符串
     * @return true|false
     */
    public static boolean isJavaNameIdentifier(String str) {
        if (isBlank(str)) return false;
        
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (i == 0 && !Character.isJavaIdentifierStart(c) || !Character.isJavaIdentifierPart(c)) {
                return false;
            }
        }
        return true;
    }
}
